package cn.kivensoft.util;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

/** 基于Map<String, Object>的增强包装类, 添加类型转换函数
 * @author kiven lee
 * @version 1.0
 * @since 2020-01-05
 */
public class MapWrap implements Map<String, Object>, Cloneable, Serializable {
	private static final long serialVersionUID = 1L;

	private final Map<String, Object> map;

	public static MapWrap of(Object... args) {
		Map<String, Object> m = new HashMap<>();
		for (int i = 0, imax = args.length - 1; i < imax; i += 2)
			m.put((String)args[i], args[i + 1]);
		return new MapWrap(m);
	}

	public static MapWrap wrap(Map<String, Object> map) {
		return new MapWrap(map);
	}

	public MapWrap() {
		this.map = new HashMap<>();
	}

	public MapWrap(Map<String, Object> value) {
		this.map = value == null ? new HashMap<>() : value;
	}

	/** 返回内部实际存储用的字典实例 */
	final public Map<String, Object> getData() {
		return map;
	}

	/** 返回该实例是否线程安全标志 */
	final public boolean isSynchronized() {
		return map instanceof ConcurrentHashMap;
	}

	/** 以Mapx的实例返回指定键的值 */
	@SuppressWarnings("unchecked")
	final public MapWrap getMap(String key) {
		Object value = get(key);
		if (value == null) return null;
		else if (value instanceof MapWrap) return (MapWrap) value;
		else if (value instanceof Map) return new MapWrap((Map<String, Object>) value);
		else return null;
	}

	@SuppressWarnings("unchecked")
	final public <T> List<T> getList(String key) {
		Object value = get(key);
		if (value == null) return null;
		else if (value instanceof List) return (List<T>) value;
		else return null;
	}

	/** 以String方式返回指定键的值, 系统会自动转换 */
	final public String getString(String key) {
		Object value = get(key);
		return value == null ? null : value.toString();
	}

	/** 以String方式返回指定键的值, 系统会自动转换 */
	final public String getString(String key, String defaultValue) {
		Object value = get(key);
		return value == null ? defaultValue : value.toString();
	}

	/** 以Integer方式返回指定键的值, 系统会自动转换 */
	final public Integer getInteger(String key) {
		return Convert.asInteger(get(key));
	}

	/** 以int方式返回指定键的值(为null时返回缺省值def), 系统会自动转换 */
	final public int getInt(String key, int defaultValue) {
		return Convert.asInt(get(key), defaultValue);
	}

	/** 以Long方式返回指定键的值, 系统会自动转换 */
	final public Long getLong(String key) {
		return Convert.asLong(get(key));
	}

	/** 以long方式返回指定键的值(为null时返回缺省值def), 系统会自动转换 */
	final public long getLong(String key, long defaultValue) {
		return Convert.asLong(get(key), defaultValue);
	}

	/** 以Boolean方式返回指定键的值, 系统会自动转换 */
	final public Boolean getBoolean(String key) {
		return Convert.asBoolean(get(key));
	}

	/** 以Boolean方式返回指定键的值, 系统会自动转换 */
	final public Boolean getBoolean(String key, boolean defaultValue) {
		return Convert.asBoolean(get(key), defaultValue);
	}

	/** 以Float方式返回指定键的值, 系统会自动转换 */
	final public Float getFloat(String key) {
		return Convert.asFloat(get(key));
	}

	/** 以Float方式返回指定键的值, 系统会自动转换 */
	final public Float getFloat(String key, float defaultValue) {
		return Convert.asFloat(get(key), defaultValue);
	}

	/** 以Double方式返回指定键的值, 系统会自动转换 */
	final public Double getDouble(String key) {
		return Convert.asDouble(get(key));
	}

	/** 以Double方式返回指定键的值, 系统会自动转换 */
	final public Double getDouble(String key, double defaultValue) {
		return Convert.asDouble(get(key), defaultValue);
	}

	/** 以Date方式返回指定键的值, 系统会自动转换 */
	final public Date getDate(String key) {
		return Convert.asDate(get(key));
	}

	/** 以LocalDate方式返回指定键的值, 系统会自动转换 */
	final public LocalDate getLocalDate(String key) {
		return Convert.asLocalDate(get(key));
	}

	/** 以LocalTime方式返回指定键的值, 系统会自动转换 */
	final public LocalTime getLocalTime(String key) {
		return Convert.asLocalTime(get(key));
	}

	/** 以LocalDateTimer方式返回指定键的值, 系统会自动转换 */
	final public LocalDateTime getLocalDateTime(String key) {
		return Convert.asLocalDateTime(get(key));
	}

	@Override
	final public int size() {
		return map.size();
	}

	@Override
	final public boolean isEmpty() {
		return map.isEmpty();
	}

	@Override
	final public boolean containsKey(Object key) {
		return map.containsKey(key);
	}

	@Override
	final public boolean containsValue(Object value) {
		return map.containsValue(value);
	}

	@Override
	final public Object get(Object key) {
		return map.get(key);
	}

	@Override
	final public Object put(String key, Object value) {
		return map.put(key, value);
	}

	@Override
	final public Object remove(Object key) {
		return map.remove(key);
	}

	@Override
	final public void putAll(Map<? extends String, ?> m) {
		map.putAll(m);
	}

	@Override
	final public void clear() {
		map.clear();
	}

	@Override
	final public Set<String> keySet() {
		return map.keySet();
	}

	@Override
	final public Collection<Object> values() {
		return map.values();
	}

	@Override
	final public Set<Entry<String, Object>> entrySet() {
		return map.entrySet();
	}

	@SuppressWarnings({"unchecked", "MethodDoesntCallSuperMethod"})
	@Override
	public MapWrap clone() {
		Class<?> cls = map.getClass();
		Object data;
		if (cls == HashMap.class)
			data = ((HashMap<String, Object>)map).clone();
		else if (cls == LinkedHashMap.class)
			data = ((LinkedHashMap<String, Object>)map).clone();
		else if (cls == TreeMap.class)
			data = ((TreeMap<String, Object>)map).clone();
		else
			data = new HashMap<>(map);
		return new MapWrap((Map<String, Object>) data);
	}

	@SuppressWarnings("unchecked")
	final public <T> T getx(String key) {
		return (T) map.get(key);
	}

	final public MapWrap putx(String key, Object value) {
		map.put(key, value);
		return this;
	}

	/** 一次行设置多个键值内容, 参数必须为偶数个 */
	final public MapWrap puts(Object... args) {
		for (int i = 0, imax = args.length - 1; i < imax; i += 2)
			map.put((String) args[i], args[i + 1]);
		return this;
	}

	final public MapWrap removex(Object key) {
		map.remove(key);
		return this;
	}

	/** 一次性移除多个键 */
	final public MapWrap removes(Object... keys) {
		for (Object key : keys) map.remove(key);
		return this;
	}

	final public MapWrap clearx() {
		map.clear();
		return this;
	}

	final public MapWrap putAllx(Map<String, Object> map) {
		this.map.putAll(map);
		return this;
	}
}
